use crate::dto::client::ClientInfo;
use crate::dto::ctx::ReqCtx;
use crate::dto::sys_oper_log::OperationLogData;
use crate::middleware::jwt::JWTClaims;
use crate::util::web_utils::get_client_info;
use hypers::{
    hyper::StatusCode,
    prelude::{hook, Error, Next, Request, Responder, Response},
    serde_json::json,
    HttpBody, Result,
};
use rbatis::rbdc::DateTime;
use std::time::Instant;

#[hook]
pub async fn operation_log_fn(mut req: Request, next: &mut Next<'_>) -> impl Responder {
    // 获取请求上下文
    let req_ctx = match req.get::<ReqCtx>("req_ctx") {
        Some(v) => v.clone(),
        None => {
            return Ok::<_, Error>(Error::Response(
                StatusCode::INTERNAL_SERVER_ERROR.as_u16(),
                json!("处理请求信息出错"),
            ));
        }
    };
    let user = match req.get::<JWTClaims>("Claims") {
        Some(v) => v.clone(),
        None => {
            return Ok::<_, Error>(Error::Response(500, json!("处理请求信息出错")));
        }
    };
    let res_v = match req.get::<String>("res_v") {
        Some(v) => v.clone(),
        None => "".to_owned(),
    };
    let remote_addr = req.remote_addr();
    let remote_ip = remote_addr.ip().to_string();
    let req_version = format!("{:?}", req.version());
    let req_data = get_body_data(&mut req).await;
    let uc = get_client_info(req.headers().clone(), remote_addr).await;

    let start_time = Instant::now();
    // 继续执行后续任务
    let mut res = next.next(req).await?;
    let duration = start_time.elapsed();
    let status = match res.body_mut() {
        HttpBody::Empty => StatusCode::NOT_FOUND,
        _ => StatusCode::OK,
    };
    // 执行结束后设置res中的数据
    // 生成一个请求id
    let req_id = scru128::new_string();
    let req_time = DateTime::now();
    let d = duration.as_micros() as i64;
    let log = OperationLogData {
        req_id,
        req_user: user.id.clone(),
        req_time: req_time.format("%Y-%m-%d %H:%M:%S %.f %Z").to_string(),
        time_id: req_time.unix_timestamp(),
        req_ip: remote_ip,
        req_version,
        req_method: req_ctx.method.clone(),
        req_url: req_ctx.path.clone(),
        req_ori_url: req_ctx.ori_uri.clone(),
        req_data,
        res_status: status.to_string(),
        res_body: res_v,
        res_time: DateTime::now()
            .format("%Y-%m-%d %H:%M:%S %.f %Z")
            .to_string(),
        elapsed_time: format!("{:?}μs", d),
    };
    match add_operation_log(&user, &req_ctx, &uc, log, d).await {
        Ok(v) => Ok::<_, Error>(Error::Response(200,json!(v))),
        Err(e) => Ok::<_, Error>(Error::Response(500, json!(format!("日志添加失败：{}", e.to_string()))))
    }
}

/// 获取请求的json数据
async fn get_body_data(req: &mut Request) -> String {
    let v = match req.payload().await {
        Ok(v) => v.clone(),
        Err(_) => "".into(),
    };
    match std::str::from_utf8(&v) {
        Ok(x) => x.to_string(),
        Err(_) => "".to_string(),
    }
}

/// 添加日志
async fn add_operation_log(
    user: &JWTClaims,
    req_ctx: &ReqCtx,
    uc: &ClientInfo,
    log: OperationLogData,
    d: i64,
) -> Result<String> {
    todo!()
}
